package com.tools.scanner.ui.pdf

import android.content.Context
import android.content.Intent
import android.net.Uri
import android.os.Bundle
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.IntentSenderRequest
import androidx.activity.result.contract.ActivityResultContracts
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.PagerSnapHelper
import androidx.recyclerview.widget.RecyclerView
import com.bumptech.glide.Glide
import com.google.mlkit.vision.documentscanner.GmsDocumentScanningResult
import com.tools.scanner.BaseActivity
import com.tools.scanner.R
import com.tools.scanner.constant.AdLocationConstant
import com.tools.scanner.ad.AdManager
import com.tools.scanner.constant.SpConstant
import com.tools.scanner.database.PdfInfo
import com.tools.scanner.database.ScannerDatabase
import com.tools.scanner.databinding.ActivityProcessPdfBinding
import com.tools.scanner.databinding.RecyclerPdfProcessBinding
import com.tools.scanner.ui.dialog.InputPdfNameDialog
import com.tools.scanner.utils.DataReportUtil
import com.tools.scanner.utils.PreferencesUtil
import com.tools.scanner.utils.ScannerPdfUtil
import com.tools.scanner.utils.ToastUtil
import com.tools.scanner.utils.formatTimestamp
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.json.JSONArray
import java.io.File

class ProcessPdfActivity : BaseActivity() {

    companion object {

        private const val SCANNING_RESULT = "scanning_result"

        fun actionStart(context: Context, scanningResult: GmsDocumentScanningResult) {
            val intent = Intent(context, ProcessPdfActivity::class.java)
            intent.putExtra(SCANNING_RESULT, scanningResult)
            context.startActivity(intent)
        }
    }

    override fun onSaveInstanceState(outState: Bundle) {
        super.onSaveInstanceState(outState)
        outState.putParcelable(SCANNING_RESULT, mScanningResult)
    }

    private lateinit var mBinding: ActivityProcessPdfBinding
    private lateinit var mScannerLauncher: ActivityResultLauncher<IntentSenderRequest>

    private val mAdapter = PdfProcessAdapter()
    private var mFileName = ""
    private val mAdLocation = AdLocationConstant.I_CREATE_PDF

    private var mScanningResult: GmsDocumentScanningResult? = null
    private var mPdfInfo: PdfInfo? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        mBinding = ActivityProcessPdfBinding.inflate(layoutInflater)
        setContentView(mBinding.root)

        mScanningResult = if (savedInstanceState != null) {
            savedInstanceState.getParcelable(SCANNING_RESULT)
        } else {
            intent.getParcelableExtra(SCANNING_RESULT)
        }

        val scanningResult = mScanningResult
        if (scanningResult == null) {
            finish()
            return
        }

        val imageList = mutableListOf<Uri>()

        scanningResult.pages?.forEach {
            imageList.add(it.imageUri)
        }
        if (imageList.isEmpty()) {
            finish()
            return
        }

        if (savedInstanceState == null) {
            AdManager.loadInterstitialAd(mAdLocation)
        }

        mScannerLauncher =
            registerForActivityResult(ActivityResultContracts.StartIntentSenderForResult()) { result ->
                if (result.resultCode == RESULT_OK) {
                    val gmsDocumentScanningResult =
                        GmsDocumentScanningResult.fromActivityResultIntent(result.data)
                            ?: return@registerForActivityResult
                    val imageUri = gmsDocumentScanningResult.pages?.get(0)?.imageUri
                        ?: return@registerForActivityResult
                    replaceUri(imageUri)
                }
            }

        mFileName = "Pdf File ${System.currentTimeMillis().formatTimestamp()}"
        mBinding.tvName.text = mFileName

        setupRecyclerView(imageList)

        mBinding.ivBack.setOnClickListener {
            finish()
        }

        mBinding.tvName.setOnClickListener {
            showNameDialog()
        }

        mBinding.ivEdit.setOnClickListener {
            mBinding.tvName.performClick()
        }

        mBinding.llLeft.setOnClickListener {
            val layoutManager = mBinding.recyclerView.layoutManager
            if (layoutManager is LinearLayoutManager) {
                val currentPosition = layoutManager.findFirstVisibleItemPosition()
                if (currentPosition > 0) {
                    mBinding.recyclerView.smoothScrollToPosition(currentPosition - 1)
                }
            }
        }

        mBinding.llRight.setOnClickListener {
            val layoutManager = mBinding.recyclerView.layoutManager
            if (layoutManager is LinearLayoutManager) {
                val currentPosition = layoutManager.findFirstVisibleItemPosition()
                if (currentPosition < mAdapter.itemCount - 1) {
                    mBinding.recyclerView.smoothScrollToPosition(currentPosition + 1)
                }
            }
        }

        mBinding.llRemake.setOnClickListener {
            remake()
        }

        mBinding.llDelete.setOnClickListener {
            delete()
        }

        mBinding.llSave.setOnClickListener {
            save()
        }
    }

    private fun setupRecyclerView(imageList: List<Uri>) {
        mBinding.tvNum.text = "1/${imageList.size}"

        val snapHelper = PagerSnapHelper()
        snapHelper.attachToRecyclerView(mBinding.recyclerView)

        val layoutManager = LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false)

        mBinding.recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() {
            override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
                super.onScrollStateChanged(recyclerView, newState)
                if (newState == RecyclerView.SCROLL_STATE_IDLE) {
                    val position = snapHelper.findTargetSnapPosition(layoutManager, 0, 0)
                    if (position != RecyclerView.NO_POSITION) {
                        mBinding.tvNum.text = "${position + 1}/${mAdapter.itemCount}"

                        if (position == 0) {
                            mBinding.ivLeft.setImageResource(R.drawable.ic_pdf_left_none)
                            mBinding.llLeft.isEnabled = false
                        } else {
                            mBinding.ivLeft.setImageResource(R.drawable.ic_pdf_left)
                            mBinding.llLeft.isEnabled = true
                        }

                        if (position == mAdapter.itemCount - 1) {
                            mBinding.ivRight.setImageResource(R.drawable.ic_pdf_right_none)
                            mBinding.llRight.isEnabled = false
                        } else {
                            mBinding.ivRight.setImageResource(R.drawable.ic_pdf_right)
                            mBinding.llRight.isEnabled = true
                        }

                    }
                }
            }
        })

        mBinding.recyclerView.layoutManager = layoutManager
        mBinding.recyclerView.adapter = mAdapter
        mAdapter.setData(imageList)
    }

    private fun remake() {
        ScannerPdfUtil.startScan(this, mScannerLauncher, 1)
    }

    private fun delete() {
        val layoutManager = mBinding.recyclerView.layoutManager
        if (layoutManager is LinearLayoutManager) {
            val currentPosition = layoutManager.findFirstVisibleItemPosition()
            if (currentPosition != RecyclerView.NO_POSITION) {
                mAdapter.removeItem(currentPosition)
            }
        }
    }

    private fun save() {
        val imageList = mAdapter.getAllData()
        if (imageList.isEmpty()) {
            return
        }

        showLoadingDialog()
        val pdfFile = File(cacheDir, "${mFileName}.pdf")
        lifecycleScope.launch(Dispatchers.IO) {
            val pdfUtil = PdfUtil()
            val result = pdfUtil.imgTransformPdf(pdfFile, imageList)

            if (!result) {
                withContext(Dispatchers.Main) {
                    hideLoadingDialog()
                    ToastUtil.showToast(R.string.pdf_make_fail)
                    DataReportUtil.reportCreatePdfFail()
                }
                return@launch
            }

            val jsonArray = JSONArray()
            imageList.forEach { uri ->
                jsonArray.put(uri.toString())
            }

            val pdfInfo = PdfInfo(
                name = mFileName,
                firstPhoto = imageList[0].toString(),
                photoPath = jsonArray.toString(),
                num = imageList.size,
                pdfPath = pdfFile.absolutePath
            )
            ScannerDatabase.get().savePdfInfo(pdfInfo)
            mPdfInfo = pdfInfo

            withContext(Dispatchers.Main) {
                DataReportUtil.reportCreatePdfSuccess()
                showPdfAd()
            }
        }
    }

    private fun showNameDialog() {
        val imageList = mAdapter.getAllData()
        if (imageList.isEmpty()) {
            return
        }

        InputPdfNameDialog(this, cacheDir, mFileName) {
            mFileName = it
            mBinding.tvName.text = mFileName
        }.show()
    }

    private fun replaceUri(uri: Uri) {
        val layoutManager = mBinding.recyclerView.layoutManager
        if (layoutManager is LinearLayoutManager) {
            val currentPosition = layoutManager.findFirstVisibleItemPosition()
            if (currentPosition != RecyclerView.NO_POSITION) {
                mAdapter.replaceItem(currentPosition, uri)
            }
        }
    }

    override fun getStatusColor(): Int {
        return resources.getColor(R.color.color_1c1c1e)
    }

    private fun showPdfAd() {
        AdManager.addStepCount(mAdLocation)

        if (!AdManager.isLoadComplete(mAdLocation)) {
            nextAdAction()
            return
        }

        AdManager.subscribeAdShowStatusEvent(mAdLocation, this) {
            if (it.status == AdManager.AdShowStatus.DISMISSED) {
                nextAdAction()
            }
        }

        AdManager.showInterstitialAd(mAdLocation, this)
    }

    private fun nextAdAction() {
        hideLoadingDialog()
        mPdfInfo?.let {
            PreviewPdfActivity.actionStart(this@ProcessPdfActivity, it, true)
            finish()
        }
    }
}

class PdfProcessAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder>() {

    private val imageList = mutableListOf<Uri>()

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
        val layoutInflater = LayoutInflater.from(parent.context)
        val binding = RecyclerPdfProcessBinding.inflate(layoutInflater, parent, false)
        return PreviewViewHolder(binding)
    }

    override fun getItemCount(): Int {
        return imageList.size
    }

    override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
        if (holder is PreviewViewHolder) {
            holder.refresh(imageList[position])
        }
    }

    fun setData(uris: List<Uri>) {
        imageList.clear()
        imageList.addAll(uris)
        notifyDataSetChanged()
    }

    fun removeItem(position: Int) {
        if (imageList.isEmpty()) {
            return
        }

        if (position < 0 || position >= itemCount) {
            return
        }

        imageList.removeAt(position)
        notifyItemRemoved(position)
    }

    fun replaceItem(position: Int, uri: Uri) {
        if (imageList.isEmpty()) {
            return
        }

        if (position < 0 || position >= itemCount) {
            return
        }

        imageList.removeAt(position)
        imageList.add(position, uri)
        notifyItemChanged(position)
    }

    fun getAllData(): List<Uri> {
        return imageList
    }

    class PreviewViewHolder(private val mBinding: RecyclerPdfProcessBinding) :
        RecyclerView.ViewHolder(mBinding.root) {
        fun refresh(uri: Uri) {
            mBinding.imageView.let {
                Glide.with(it).load(uri).into(it)
            }
        }
    }
}
